import json
from typing import Annotated

from fastapi import APIRouter, Depends, Form
from starlette import status

from dc_shop.core.models.dto import ProductDTO
from dc_shop.core.utils.order import calculate_product_discount
from dc_shop.database.models import CartProduct
from dc_shop.database.services.discount import DiscountService
from dc_shop.database.services.product import ProductService
from dc_shop.database.services.shop import ShopService
from dc_shop.database.services.user import UserService
from dc_shop.webapp.app.providers.stub import Stub

products_router = APIRouter(prefix="/products", tags=["products"])


@products_router.get(
    "/{product_id}",
    responses={
        status.HTTP_200_OK: {"model": ProductDTO},
    },
)
async def get_product(
    product_id: int,
    user_tg_id: int,
    products_service: Annotated[ProductService, Depends(Stub(ProductService))],
    user_service: Annotated[UserService, Depends(Stub(UserService))],
    shop_service: Annotated[ShopService, Depends(Stub(ShopService))],
):
    user = await user_service.get_user_by_telegram_id(user_tg_id)
    product = await products_service.get_product_by_id(product_id)
    shop = await shop_service.get_shop_by_delivery_zone_id(user.delivery_zone_id)

    available_quantity = await products_service.get_product_available_quantity(shop.id, product.id)
    product.available_quantity = available_quantity

    return product


@products_router.get(
    "/",
    responses={
        status.HTTP_200_OK: {"model": list[ProductDTO]},
    },
    description="Return all categories and products",
)
async def get_products(
    user_tg_id: int,
    products_service: Annotated[ProductService, Depends(Stub(ProductService))],
    user_service: Annotated[UserService, Depends(Stub(UserService))],
    shop_service: Annotated[ShopService, Depends(Stub(ShopService))],
):
    user = await user_service.get_user_by_telegram_id(user_tg_id)
    products, categories = await products_service.get_products_and_categories(user.delivery_zone_id)
    shop = await shop_service.get_shop_by_delivery_zone_id(user.delivery_zone_id)
    for product in products:
        available_quantity = await products_service.get_product_available_quantity(shop.id, product.id)
        product.available_quantity = available_quantity

    return products, categories


@products_router.post(
    "/calculate_discount/",
    description="Calculate discount based on product, category and shop",
)
async def calculate_discount(
    cart_data: Annotated[str, Form()],
    user_tg_id: int,
    product_id: int,
    product_count: int,
    products_service: Annotated[ProductService, Depends(Stub(ProductService))],
    user_service: Annotated[UserService, Depends(Stub(UserService))],
    shop_service: Annotated[ShopService, Depends(Stub(ShopService))],
    discount_service: Annotated[DiscountService, Depends(Stub(DiscountService))],
):
    cart_data = json.loads(cart_data)
    user = await user_service.get_user_by_telegram_id(user_tg_id)
    product = await products_service.get_product_by_id(product_id)
    category = await products_service.get_category_by_id(product.category_id)

    # Получаем товары в категории и их количество
    cart_items = [CartProduct(product_id=item["id"], quantity=item["count"]) for item in cart_data.get("items")]
    cart_products = [await products_service.get_product_by_id(cart_product.product_id) for cart_product in cart_items]

    # Фильтруем продукты в одной категории и получаем их кол-во в корзине
    category_products_ids = [product.id for product in cart_products if product.category_id == category.id]
    category_products_quantity = sum(
        product.quantity for product in cart_items if product.product_id in category_products_ids
    )

    shop = await shop_service.get_shop_by_delivery_zone_id(user.delivery_zone_id)
    # Получаем скидку по количеству товаров в категории
    discount = await discount_service.get_discount_by_category_and_shop(
        product.category_id, shop.id, category_products_quantity
    )
    if discount and not discount.works_inside_category:
        # Получаем скидку по product_count, если скидка не распространяется на категорию
        discount = await discount_service.get_discount_by_category_and_shop(product.category_id, shop.id, product_count)
    discounted_price = (
        calculate_product_discount(product.price, discount.discount_percent) if discount else product.price
    )

    return discounted_price
